/**
 * 根据Cron表达式计算下次执行时间
 * @param {string} cronExpression - Cron表达式，格式为："分 时 日 月 周"
 * @param {Date} [currentDate=new Date()] - 当前日期时间，默认为现在
 * @param {boolean} [formatted=true] - 是否返回格式化的字符串，默认为true
 * @returns {string|Date} 格式化的下次执行时间(YYYY-MM-DD HH:mm:ss)或Date对象
 */
function getNextCronTime(cronExpression, currentDate = new Date(), formatted = true) {

	if (!cronExpression) {
		return "";
	}

	// 解析Cron表达式
	const [minute, hour, dayOfMonth, month, dayOfWeek] = cronExpression.split(' ');

	// 解析Cron字段
	const parseField = (field, min, max) => {
		if (field === '*') {
			return Array.from({
				length: max - min + 1
			}, (_, i) => min + i);
		}

		const values = [];
		const parts = field.split(',');

		for (const part of parts) {
			if (part.includes('-')) {
				const [start, end] = part.split('-').map(Number);
				for (let i = start; i <= end; i++) {
					values.push(i);
				}
			} else if (part.includes('/')) {
				const [range, step] = part.split('/');
				const start = range === '*' ? min : Number(range);
				for (let i = start; i <= max; i += Number(step)) {
					values.push(i);
				}
			} else {
				values.push(Number(part));
			}
		}

		return [...new Set(values)].sort((a, b) => a - b);
	};

	const minutes = parseField(minute, 0, 59);
	const hours = parseField(hour, 0, 23);
	const daysOfMonth = parseField(dayOfMonth, 1, 31);
	const months = parseField(month, 1, 12);
	const daysOfWeek = parseField(dayOfWeek, 0, 6); // 0-6，0表示周日

	// 克隆当前日期
	const nextDate = new Date(currentDate);

	// 设置秒和毫秒为0
	nextDate.setSeconds(0);
	nextDate.setMilliseconds(0);

	// 寻找下一个执行时间点
	while (true) {
		// 检查分钟
		const nextMinute = minutes.find(m => m > nextDate.getMinutes());
		if (nextMinute !== undefined) {
			nextDate.setMinutes(nextMinute);
			continue;
		}

		// 需要进位到小时
		nextDate.setMinutes(minutes[0]);
		nextDate.setHours(nextDate.getHours() + 1);

		// 检查小时
		const nextHour = hours.find(h => h >= nextDate.getHours());
		if (nextHour !== undefined) {
			nextDate.setHours(nextHour);
			continue;
		}

		// 需要进位到天
		nextDate.setHours(hours[0]);
		nextDate.setDate(nextDate.getDate() + 1);

		// 这部分比较复杂，需要同时考虑月份天数和星期
		const currentMonth = nextDate.getMonth() + 1; // JavaScript月份从0开始
		const currentDayOfMonth = nextDate.getDate();
		const currentDayOfWeek = nextDate.getDay(); // 0-6，0表示周日

		// 检查月份
		if (!months.includes(currentMonth)) {
			// 调整到下一个有效月份的第一天
			const nextMonth = months.find(m => m > currentMonth);
			if (nextMonth !== undefined) {
				nextDate.setMonth(nextMonth - 1);
				nextDate.setDate(1);
			} else {
				nextDate.setMonth(months[0] - 1);
				nextDate.setDate(1);
				nextDate.setFullYear(nextDate.getFullYear() + 1);
			}
			continue;
		}

		// 检查日期和星期
		const validDayOfMonth = dayOfMonth === '*' || daysOfMonth.includes(currentDayOfMonth);
		const validDayOfWeek = dayOfWeek === '*' || daysOfWeek.includes(currentDayOfWeek);

		if ((validDayOfMonth && validDayOfWeek) ||
			(dayOfMonth === '*' && validDayOfWeek) ||
			(dayOfWeek === '*' && validDayOfMonth)) {
			break; // 找到了有效的日期
		}

		// 移动到下一天继续检查
		nextDate.setDate(nextDate.getDate() + 1);
	}

	// 如果需要格式化输出
	if (formatted) {
		return formatDate(nextDate);
	}

	return nextDate;
}

/**
 * 将日期格式化为 YYYY-MM-DD HH:mm:ss 字符串
 * @param {Date} date - 要格式化的日期
 * @returns {string} 格式化后的日期字符串
 */
function formatDate(date) {
	const pad = (num) => String(num).padStart(2, '0');

	const year = date.getFullYear();
	const month = pad(date.getMonth() + 1);
	const day = pad(date.getDate());
	const hours = pad(date.getHours());
	const minutes = pad(date.getMinutes());
	const seconds = pad(date.getSeconds());

	return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
}

export default getNextCronTime;
